package repo

import "container/list"

type DependencyTree struct {
	Label  string
	Childs []*DependencyTree
}

func NewDependencyTree(label string) *DependencyTree {
	return &DependencyTree{
		Label:  label,
		Childs: nil,
	}
}

func BuildDependencyTree(label string) (*DependencyTree, error) {
	queue := list.New()
	dependencyMap := make(map[string]*DependencyTree)

	// 初始化基础设施
	rootTree := NewDependencyTree(label)
	queue.PushBack(rootTree)
	dependencyMap[label] = rootTree

	for item := queue.Front(); item != nil; item = queue.Front() {
		// 从队列中移出
		queue.Remove(item)

		currTree := item.Value.(*DependencyTree)

		// 如果 childs 不为 nil 说明已经处理过了
		if currTree.Childs != nil {
			continue
		}

		// 如果还没有处理过子节点，那么给 currTree.Childs 赋予非 nil 值
		//currTree.Childs = make([]*DependencyTree, 0, 1)
		//currTree.Refs = make(map[string]*DependencyTree)

		// 读取 VERSION 文件，获得依赖信息
		currDesc, err := ReadModuleVersionDescription(currTree.Label)
		if err != nil {
			return nil, err
		}

		// 登记新发现的依赖项，并追加到列表中
		for _, requiredModuleLabel := range currDesc.RequiredModules {
			// 尝试根据 Label 找到登记过的依赖项
			childTree, ok := dependencyMap[requiredModuleLabel]

			// 如果依赖项还没登记过，登记一下，并加入待处理列表
			if !ok {
				childTree = NewDependencyTree(requiredModuleLabel)
				dependencyMap[requiredModuleLabel] = childTree
				queue.PushBack(childTree)
			}

			// 所有子依赖都加入父节点
			currTree.Childs = append(currTree.Childs, childTree)
		}
	}

	return rootTree, nil
}

type EnumFootprint struct {
	items map[string]bool
}

func (f *EnumFootprint) Exists(label string) bool {
	_, exists := f.items[label]
	return exists
}

func enumDependencyTree(depth int, root *DependencyTree, before func(depth int, tree *DependencyTree) bool, after func(depth int, tree *DependencyTree)) {

	//// 如果曾经已经处理过，就不需要了
	//if footprint.Exists(root.Label) {
	//	return
	//}

	if before != nil {
		if !before(depth, root) {
			return
		}
	}

	for _, child := range root.Childs {
		enumDependencyTree(depth+1, child, before, after)
	}

	if after != nil {
		after(depth, root)
	}
}

func EnumDependencyTree(depth int, root *DependencyTree, before func(depth int, tree *DependencyTree) bool, after func(depth int, tree *DependencyTree)) {
	enumDependencyTree(depth, root, before, after)
}
